﻿#region Copyright (c) 2011, thinktecture (http://www.thinktecture.com)

/*
   thinktecture.UIAnnotations was developed by Jörg Neumann.
   Copyright (c) 2011, thinktecture (http://www.thinktecture.com).
   All rights reserved, comes as-is and without any warranty. Use of this
   source file is governed by the license which is contained in LICENSE.TXT 
   in the distribution.
*/

#endregion

using System;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media.Imaging;
using System.Windows.Controls;
using System.Windows.Data;
using System.ComponentModel;
using System.Reflection;
using System.Windows.Media;
using System.Collections.Generic;

namespace Thinktecture.UIAnnotations
{
    public class EditTrackerAdorner : Adorner, IDisposable
    {
        private bool _showTracker;
        private ExtensionImageAlignment _alignment;
        private Dictionary<DependencyObject, DependencyPropertyDescriptor> _propertyDescriptors;
        private bool _draw = false;
        
        public EditTrackerAdorner(UIElement adornedElement)
            : base(adornedElement)
        {
            _propertyDescriptors = new Dictionary<DependencyObject, DependencyPropertyDescriptor>();
            this.Focusable = false;
            _showTracker = true;
            _alignment = ExtensionImageAlignment.Right;
        }

        public EditTrackerAdorner(UIElement adornedElement, 
            bool showTracker,
            ExtensionImageAlignment alignment)
            : base(adornedElement)
        {
            _propertyDescriptors = new Dictionary<DependencyObject, DependencyPropertyDescriptor>();
            this.Focusable = false;
            _showTracker = showTracker;
            _alignment = alignment;
        }

        protected override void OnRender(System.Windows.Media.DrawingContext drawingContext)
        {
            Rect targetRect;
            if (this.Alignment == ExtensionImageAlignment.Right)
            {
                targetRect = new Rect(
                    new Point(this.AdornedElement.RenderSize.Width + 3, (this.AdornedElement.RenderSize.Height - 18) / 2),
                    new Size(18, 18));
            }
            else
            {
                targetRect = new Rect(
                    new Point(-20, (this.AdornedElement.RenderSize.Height - 17) / 2),
                    new Size(18, 18));
            }
            if (_draw)
            {
                _draw = false;
                BitmapImage trackerIcon = new BitmapImage();
                trackerIcon.BeginInit();
                Uri imageUri = new Uri("pack://application:,,,/Thinktecture.UIAnnotations;component/Images/Edit.png");
                trackerIcon.UriSource = imageUri;
                trackerIcon.EndInit();
                drawingContext.DrawImage(trackerIcon, targetRect);
            }
            this.DrawEditImage((FrameworkElement)this.AdornedElement, drawingContext);
        }

        private void DrawEditImage(FrameworkElement element, DrawingContext drawingContext)
        {
            if (element.TemplatedParent != null)
            {
                element = element.TemplatedParent as FrameworkElement;
            }
            FieldInfo[] properties = element.GetType().GetFields(BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.Static | BindingFlags.FlattenHierarchy);
            foreach (FieldInfo field in properties)
            {
                if (field.FieldType == typeof(DependencyProperty))
                {
                    DependencyProperty dp = (DependencyProperty)field.GetValue(null);
                    if (BindingOperations.IsDataBound(element, dp))
                    {
                        DependencyPropertyDescriptor descriptor = DependencyPropertyDescriptor.FromProperty(dp, element.GetType());
                        if (descriptor != null)
                        {
                            if (!_propertyDescriptors.ContainsKey(element))
                            {
                                _propertyDescriptors.Add(element, descriptor);
                                descriptor.AddValueChanged(element, this.OnValueChanged);
                            }
                        }
                    }
                }
            }
        }

        public ExtensionImageAlignment Alignment
        {
            get { return _alignment; }
            set { _alignment = value; this.InvalidateVisual(); }
        }

        public bool ShowTracker
        {
            get { return _showTracker; }
            set { _showTracker = value; this.InvalidateVisual(); }
        }

        #region Event Handling

        private void OnValueChanged(object sender, EventArgs e)
        {
            _draw = true;
            this.InvalidateVisual();
        }
        
        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            if (_propertyDescriptors != null)
            {
                foreach (DependencyObject element in _propertyDescriptors.Keys)
                {
                    DependencyPropertyDescriptor descriptor = _propertyDescriptors[element];
                    descriptor.RemoveValueChanged(element, this.OnValueChanged);
                }
            }
        }

        #endregion
    }
}
